import cmath
import random
import math
import calendar
import datetime
import re


# Hello World 实例
def hello_world():
    print('### Hello World 实例')
    print('Hello World!')


# 数字求和实例
def get_sum(a, b):
    print('### 数字求和实例')
    print('两数之和为{:0.1f}'.format(float(a) + float(b)))


# 平方根实例
def get_sqrt(a):
    print('### 平方根实例')
    if type(a) is complex or a < 0:
        num_sqrt = cmath.sqrt(a)
        print('{0} 的平方根为 {1:0.3f}+{2:0.3f}j'.format(a, num_sqrt.real, num_sqrt.imag))
    else:
        print('{:0.3f}的平方根为{:0.3f}'.format(a, a ** 0.5))


# 二次方程
# a、b、c 用户提供，为实数，a ≠ 0
def get_quadratic_equation(a, b, c):
    print('### 二次方程实例')
    # 计算
    d = (b ** 2) - (4 * a * c)
    # 两种求解方式
    sol1 = (-b - cmath.sqrt(d)) / (2 * a)
    sol2 = (-b + cmath.sqrt(d)) / (2 * a)
    print('结果为 {0} 和 {1}'.format(sol1, sol2))


# 计算三角形的面积
def get_triangle_area(a, b, c):
    print('### 计算三角形的面积实例')
    # 计算半周长
    s = (a + b + c) / 2
    # 计算面积
    area = (s * (s - a) * (s - b) * (s - c)) ** 0.5
    print('三角形面积为 %0.2f' % area)


# 计算圆的面积
def get_circle_area(r):
    print('### 计算圆的面积实例')
    pi = cmath.pi
    print("圆的面积为{:.6f}".format(pi * (r ** 2)))


# 随机数生成
def get_randint(a, b):
    print('### 随机数生成实例')
    print(random.randint(a, b))


# 摄氏温度转华氏温度
def celsius2fahrenheit(celsius):
    print('### 摄氏温度转华氏温度实例')
    fahrenheit = (celsius * 1.8) + 32
    print('{0:0.1f} 摄氏温度等于 {1:0.1f} 华氏温度'.format(celsius, fahrenheit))


# 交换变量
def swap(x, y):
    print('### 交换变量实例')
    x, y = y, x
    print('交换后 x 的值为: {}'.format(x))
    print('交换后 y 的值为: {}'.format(y))


# if语句
def sample_if(n):
    print('### if语句实例')
    if n > 0:
        print("正数")
    elif n == 0:
        print("零")
    else:
        print("负数")


# 判断字符串是否为数字
#  isdigit() 方法检测字符串是否只由数字组成。
#  isnumeric() 方法检测字符串是否只由数字组成。这种方法是只针对unicode对象。
def is_number(s):
    print('### 判断字符串是否为数字实例')
    # 判断字符串和数字
    try:
        float(s)  # 如果能运行float(s)语句，返回True（字符串s是浮点数）
        print('是数字')
        return
    except ValueError:
        pass
    # 判断Unicode
    try:
        import unicodedata
        unicodedata.numeric(s)  # 把一个表示数字的字符串转换为浮点数返回的函数
        print('是数字')
        return
    except (TypeError, ValueError):
        pass
    print('不是数字')


# 判断奇数偶数
def is_odd_or_even(s):
    print('### 判断奇数偶数实例')
    if (s % 2) == 0:
        print("{0} 是偶数".format(s))
    else:
        print("{0} 是奇数".format(s))


# 判断闰年
def is_leap_year(year):
    print('### 判断闰年实例')
    if (year % 4) == 0:
        if (year % 100) == 0:
            if (year % 400) == 0:
                print("{0} 是闰年".format(year))  # 整百年能被400整除的是闰年
            else:
                print("{0} 不是闰年".format(year))
        else:
            print("{0} 是闰年".format(year))  # 非整百年能被4整除的为闰年
    else:
        print("{0} 不是闰年".format(year))


# 获取最大值函数
# 支持列表和元组
def get_max(a):
    print('### 获取最大值函数实例')
    print(max(a))


# 质数判断
def is_prime(n):
    print('### 质数判断实例')
    # 质数大于 1
    if n > 1:
        # 查看因子
        for i in range(2, n):
            if (n % i) == 0:
                print(n, "不是质数")
                break
        else:
            print(n, "是质数")
    # 如果输入的数字小于或等于 1，不是质数
    else:
        print(n, "不是质数")


# 输出指定范围内的质数
def get_prime(a, b):
    print('### 输出指定范围内的质数实例')
    for num in range(a, b + 1):
        # 素数大于 1
        if num > 1:
            for i in range(2, num):
                if (num % i) == 0:
                    break
            else:
                print(num, end=' ')
    print()


# 阶乘
def get_factorial(n):
    print('### 阶乘实例')
    if n < 0:
        print("抱歉，负数没有阶乘")
    elif n == 0:
        print("0 的阶乘为 1")
    else:
        print("{0} 的阶乘为 {1}".format(n, math.factorial(n)))


# 九九乘法表
def get_multiplication_table():
    print('### 九九乘法表实例')
    for i in range(1, 10):
        for j in range(1, i + 1):
            print('{}x{}={}\t'.format(j, i, i * j), end='')
        print()


# 斐波那契数列
# 斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13,特别指出：第0项是0，第1项是第一个1。从第三项开始，每一项都等于前两项之和。
# 取值范围可以用 a, b = b, a + b
# 斐波那契数列的通项式为:f(n) = (5**0.5/5)*(((1+5**0.5)/2)**n - ((1-5**0.5)/2)**n)
def get_fibonacci_sequence(n):
    print('### 斐波那契数列实例')
    if n <= 0:
        print("请输入大于0的数")
    else:
        for i in range(n):
            print(int((5**0.5/5)*(((1+5**0.5)/2)**i - ((1-5**0.5)/2)**i)), end=" ")
        print()


# 阿姆斯特朗数
# 如果一个n位正整数等于其各位数字的n次方之和,则称该数为阿姆斯特朗数。 例如1^3 + 5^3 + 3^3 = 153。
def is_armstrong_number(num):
    print('### 判断阿姆斯特朗数实例')
    n = len(str(num))
    s = 0
    temp = num
    while temp > 0:
        s += ((temp % 10) ** n)
        temp //= 10
    if s == num:
        print(num, "是阿姆斯特朗数")
    else:
        print(num, "不是阿姆斯特朗数")


# 获取指定期间内的阿姆斯特朗数
def get_armstrong_number(a, b):
    print('### 获取指定期间内的阿姆斯特朗数实例')
    for num in range(a, b+1):
        n = len(str(num))
        s = 0
        temp = num
        while temp > 0:
            s += ((temp % 10) ** n)
            temp //= 10
        if s == num:
            print(num, end=" ")
    print()


# 十进制转二进制、八进制、十六进制
def convert_base(n):
    print('### 十进制转二进制、八进制、十六进制实例')
    print("十进制数为：", n)
    print("转换为二进制为：", bin(n))
    print("转换为八进制为：", oct(n))
    print("转换为十六进制为：", hex(n))


# ASCII码与字符相互转换
def convert_str2asc(a, c):
    print('### ASCII码与字符相互转换实例')
    print(c + " 的ASCII 码为", ord(c))
    print(a, " 对应的字符为", chr(int(a)))


# 最大公约数算法(Greatest Common Divisor)
def get_gcd(x, y):
    print('### 最大公约数算法实例')
    # 获取最小值
    if x > y:
        smaller = y
    else:
        smaller = x
    hcf = 1
    for i in range(1, smaller + 1):
        if(x % i == 0) and (y % i == 0):
            hcf = i
    print(x, "和", y, "的最大公约数为", hcf)


# 最小公倍数算法(Least Common Multiple)
def get_lcm(x, y):
    print('### 最小公倍数算法实例')
    #  获取最大的数
    if x > y:
        greater = x
    else:
        greater = y

    while True:
        if(greater % x == 0) and (greater % y == 0):
            lcm = greater
            break
        greater += 1
    print(x, "和", y, "的最小公倍数为", lcm)


# 生成日历
def get_calendar(yy, mm):
    print('### 生成日历实例')
    print(calendar.month(yy, mm))


# 使用递归斐波那契数列
def recursion_fibonacci_sequence(n):
    print('### 使用递归斐波那契数列实例')

    def func(num):
        # 内部递归函数 输出斐波那契数列
        if num <= 1:
            return num
        else:
            return func(num - 1) + func(num - 2)

    for i in range(n):
        print(func(i), end=" ")
    print()


# 字符串判断
def str_type(s):
    print('### 字符串判断实例')
    if str(s).isalnum():
        print('字符都是数字或者字母')
    if str(s).isalpha():
        print('字符都是字母')
    if str(s).isdigit():
        print('字符都是数字')
    if str(s).islower():
        print('字符都是小写')
    if str(s).isupper():
        print('字符都是大写')
    if str(s).istitle():
        print('单词都是首字母大写，像标题')
    if str(s).isspace():
        print(r'字符都是空白字符、\t、\n、\r')


# 字符串大小写转换
def convert_str(s):
    print('### 字符串大小写转换实例')
    print(s.upper())  # 把所有字符中的小写字母转换成大写字母
    print(s.lower())  # 把所有字符中的大写字母转换成小写字母
    print(s.capitalize())  # 把第一个字母转化为大写字母，其余小写
    print(s.title())  # 把每个单词的第一个字母转化为大写，其余小写


# 计算每个月天数
def get_month_day(yy, mm):
    print('### 计算每个月天数实例')
    print(calendar.monthrange(yy, mm))


# 获取昨天日期
def get_yesterday():
    print('### 获取昨天日期实例')
    today = datetime.date.today()
    day = datetime.timedelta(days=1)
    yesterday = today - day
    print(yesterday)


# 约瑟夫生者死者小游戏
# 30 个人在一条船上，超载，需要 15 人下船。
# 于是人们排成一队，排队的位置即为他们的编号。
# 报数，从 1 开始，数到 9 的人下船。
# 如此循环，直到船上仅剩 15 人为止，问都有哪些编号的人下船了呢？
def game1():
    print('### 约瑟夫生者死者小游戏实例')
    people = {}
    for x in range(1, 31):
        people[x] = 1
    check, i, j = 0, 1, 0
    people_list = []
    while i <= 31:
        if i == 31:
            i = 1
        elif j == 15:
            break
        else:
            if people[i] == 0:
                i += 1
                continue
            else:
                check += 1
                if check == 9:
                    people[i] = 0
                    check = 0
                    people_list.append(i)
                    j += 1
                else:
                    i += 1
                    continue
    print("{}号下船了".format(",".join([str(i) for i in people_list])))


# 五人分鱼
# A、B、C、D、E 五人在某天夜里合伙去捕鱼，到第二天凌晨时都疲惫不堪，于是各自找地方睡觉。
# 日上三杆，A 第一个醒来，他将鱼分为五份，把多余的一条鱼扔掉，拿走自己的一份。
# B 第二个醒来，也将鱼分为五份，把多余的一条鱼扔掉拿走自己的一份。 。
# C、D、E依次醒来，也按同样的方法拿鱼。
# 问他们台伙至少捕了多少条鱼?
def game2():
    print('### 五人分鱼实例')
    fish = 1
    while True:
        total, enough = fish, True
        for _ in range(5):
            if (total - 1) % 5 == 0:
                total = (total - 1) // 5 * 4
            else:
                enough = False
                break
        if enough:
            print(f'总共有{fish}条鱼')
            break
        fish += 1


# 计算 n 个自然数的立方和
def get_cube_sum(n):
    print('### 计算 n 个自然数的立方和实例')
    s = 0
    for i in range(1, n + 1):
        s += i ** 3
    print(s)


# 计算数组元素之和
def get_arr_sum(arr):
    print('### 计算数组元素之和实例')
    s = sum(arr)
    print(s)


# 数组翻转指定个数的元素
def reverse_array(arr, n):
    print('### 数组翻转指定个数的元素实例')
    new_arr = arr[n:] + arr[0:n]
    print(new_arr)


# 将列表中的头尾两个元素对调
def reverse_array_start_end(arr):
    print('### 将列表中的头尾两个元素对调实例')
    reverse_array(arr, 1)


# 将列表中的指定位置的两个元素对调
# 定义一个列表，并将列表中的指定位置的两个元素对调。
# 从0开始
def swap_list_pos(arr, pos1, pos2):
    print('### 将列表中的指定位置的两个元素对调实例')
    arr[pos1], arr[pos2] = arr[pos2], arr[pos1]
    print(arr)


# 翻转列表
def reverse_list(li):
    print('### 翻转列表实例')
    print(li[-1::-1])
    li.reverse()  # => li = li[-1::-1]
    print(li)


# 列表常用操作
def list_common_operations(li):
    print('### 列表常用操作')
    print('查看 4 是否在列表中:', 4 in li)
    li_copy = li[:]
    print("复制后列表:", li_copy)
    li_copy.clear()
    print("清空后:", li_copy)
    print('查看 8 在列表的个数:', li.count(8))
    print("列表元素之和为:", sum(li))
    r = 1
    for i in li:
        r *= i
    print("列表元素之积为:", r)
    print("最大元素为:", max(li))
    print("最小元素为:", min(li))


# 移除字符串中的指定位置字符
def remove_str_pos(s, n):
    print('### 移除字符串中的指定位置字符')
    new_str = s[0:n-1] + s[n:]
    print(new_str)


# 使用正则表达式提取字符串中的 URL
def find_url(s):
    print('### 使用正则表达式提取字符串中的 URL实例')
    # findall() 查找匹配正则表达式的字符串
    r = re.findall('https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', s)
    print(r)


# 将字符串作为代码执行
def exec_code(s):
    print('### 将字符串作为代码执行实例')
    exec(s)


# 字符串翻转
def reverse_str(s):
    print('### 字符串翻转实例')
    print(s[::-1])
    print(''.join(reversed(s)))


# 对字符串切片及翻转
def reverse_str_pos(s, n):
    print('### 对字符串切片及翻转')
    print("头部切片翻转:", s[n:] + s[:n])
    print("尾部切片翻转:", s[-n:] + s[:-n])


if __name__ == '__main__':
    hello_world()
    get_sum(1, 2)
    get_sqrt(8)
    get_sqrt(-8)
    get_quadratic_equation(1, 5, 6)
    get_triangle_area(5, 6, 7)
    get_circle_area(5)
    get_randint(0, 9)
    celsius2fahrenheit(38)
    swap(x=1, y=2)
    sample_if(5)
    is_number('11212')
    is_number('四')
    is_odd_or_even(3)
    is_leap_year(2000)
    get_max([2, 5])
    is_prime(5)
    get_prime(1, 100)
    get_factorial(6)
    get_multiplication_table()
    get_fibonacci_sequence(10)
    is_armstrong_number(153)
    get_armstrong_number(0, 1000)
    convert_base(100)
    convert_str2asc(101, 'a')
    get_gcd(54, 24)
    get_lcm(54, 24)
    get_calendar(2020, 7)
    recursion_fibonacci_sequence(10)
    str_type('asfsfsdfsdf')
    convert_str('asd asfa sfsaf')
    get_month_day(2020, 7)
    get_yesterday()
    game1()
    game2()
    get_cube_sum(5)
    get_arr_sum([1, 2, 3])
    reverse_array([1, 2, 3, 4, 5, 6, 7, 8], 2)
    reverse_array_start_end([1, 2, 3, 4, 5, 6, 7, 8])
    swap_list_pos([1, 2, 3, 4, 5, 6, 7, 8], 3, 4)
    reverse_list([1, 2, 3, 4, 5, 6, 7, 8])
    list_common_operations([1, 2, 3, 4, 8, 8])
    remove_str_pos('Runoob', 3)
    find_url('Google 的网页地址为：https://www.google.com')
    exec_code('print("执行代码")')
    reverse_str('test')
    reverse_str_pos('google', 2)
